package Syntax_Anlayzer;

import java.util.*;

public class First {
    static Init init;

    public First(Init init) {
        First.init = init;
    }
    public static Map<String, Set<String>> first = new HashMap<>();

    // 生成first集合
    private void initFirst() {
        // 将所有终结符添加到first集合中
        for (String a : Init.V_T) {
            first.put(a, new HashSet<>());
            first.get(a).add(a);
        }
    }

    public static void addVNIntoFirst(String v) {
        // 初始化first集合，如果已经存在则直接返回
        if (!first.containsKey(v)) {
            first.put(v, new HashSet<>());
        } else {
            return;
        }

        // 获取非终结符v的所有产生式
        Set<List<String>> vProductions = Init.Production.get(v);

        // 遍历每个产生式
        for (List<String> production : vProductions) {
            // 遍历产生式右侧的每个符号
            for (int i = 0; i < production.size(); i++) {
                String symbol = production.get(i);

                // 如果符号是非终结符
                if (Init.V_N.contains(symbol)) {
                    // 如果first集合中不包含该非终结符，则递归构建它的first集合
                    if (!first.containsKey(symbol)) {
                        addVNIntoFirst(symbol);
                    }

                    // 将非终结符的first集合中的元素（除了'$'）添加到当前非终结符的first集合中
                    for (String firstSymbol : first.get(symbol)) {
                        if (!firstSymbol.equals("$")) {
                            first.get(v).add(firstSymbol);
                        }
                    }

                    // 如果非终结符的first集合不包含'$'，则终止当前循环
                    if (!first.get(symbol).contains("$")) {
                        break;
                    }
                } else {
                    // 如果符号是终结符，直接添加到当前非终结符的first集合中，并终止循环
                    first.get(v).add(symbol);
                    break;
                }
            }

            // 如果所有符号都遍历完了，且每个非终结符的first集合都包含'$'，则添加'$'到当前非终结符的first集合中
            if (production.size() == 0 || production.stream().allMatch(s -> first.get(s).contains("$"))) {
                first.get(v).add("$");
            }
        }
    }
    public void constructFirst() {
        initFirst();
        for (String s : Init.V_N) {
            addVNIntoFirst(s);
        }
    }

    // 获取给定符号的FIRST集
    public static Set<String> getFirstSet(String symbol) {
        return first.getOrDefault(symbol, Collections.emptySet());
    }
    public void constructFollow() {
        Follow.constructFollow();
    }
}